//CityCabo - José Cabo Carsí - folcwine@gmail.com

//Defs START
var gridUnit = {};
gridUnit.x = 10;
gridUnit.y = 10;

var houseUnit = {};
houseUnit.x = 3;
houseUnit.y = 3;

var roadUnit = {};
roadUnit.x = 2;
roadUnit.y = 2;

var act = {};
act.noaction = 0;
act.road = 1;
act.house = 2;
act.remove = 3;

var d = {}; //Defs
	d.emp = {};
		d.emp.month = 10000;//5*60*1000;
	d.u = {}; //Unit defs
		d.u.nisoGridBox = {x: 20, y:20}; //Non isometric unit grid box size
		d.u.road = {x:1 , y:1};
		d.u.house = {x:3 , y:3};
	d.config = {}; //Config defs
		d.config.EPV = false;
	d.e = {}; //Element related vars
		d.e.c = {}; //Class element related vars
			d.e.c.body = {};
				d.e.c.body.inmigrant = 'inmigrant';
			d.e.c.road = {}; //Class element for roads related vars
				d.e.c.road.mouseshadow = 'mouseroadShadow';
				d.e.c.road.shadow = 'roadShadow';
				d.e.c.road.normal = 'roadNormal';
			d.e.c.houseZone = {};
				d.e.c.houseZone.hz = 'houseZone';
				d.e.c.houseZone.shadow = 'HouseZoneShadow';
				d.e.c.houseZone.hznormal = 'houseZoneNormal';
	d.b = {};
		d.b.t = {};
			d.b.t.inmigrant = 'inmigrant';
			d.b.t.emigrant = 'emigrant';
	d.tt = {}; //Tile Types related vars
	d.tt.road = 'road';
	d.tt.houseZoneTile = 'houseZoneTile';
//Defs END
	
var CaboCity = {};
CaboCity = new Class(/** @lends CaboCity# */{
	/**
	 * @namespace
	 * @class Superobjeto y namespace de CaboCity.
	 * @constructs
	 * @property {CaboCity.Views} views
	 * @property {CaboCity.Interaction} interaction
	 */
	initialize: function(){
		
	}
});

/**
 * Contiene todos los tipos.
 * @namespace
 * */
CaboCity.t = {};

/**
 * A simple function that return true.
 * @function
 * @return boolean
 * */
CaboCity.t.TrueFunc = Function.from(true);

CaboCity.t.Point = new Class(/** @lends CaboCity.t.Point# */{
	/**
	 * @class Tipo de dato "Punto"
	 * @property {Integer} x Posición X del punto.
	 * @property {Integer} y Posición Y del punto.
	 * 
	 * @constructs
	 * @param {Integer} x Posición X del punto.
	 * @param {Integer} y Posición Y del punto.
	 * */
	initialize: function(x,y){
		
	}
});

CaboCity.t.Size = new Class(/** @lends CaboCity.t.Size#*/{
	/**
	 * @class Tipo de dato "Size"
	 * @property {Integer} w Ancho del tamaño en el plano.
	 * @property {Integer} h Altura del tamaño en el plano.
	 * 
	 * @constructs
	 * @param {Integer} w Ancho del tamaño en el plano.
	 * @param {Integer} h Altura del tamaño en el plano.
	 * */
	initialize: function(w,h){
		
	}
});
 /**
  * Contiene todas las definiciones del motor organizadas.
  * @namespace
  * */
CaboCity.t.def = {};

/**
 * Contiene las clases de los objetos de carga de builds, wt, etc.. del juego.
 * @namespace
 * */
CaboCity.t.def.Functions = {};

CaboCity.t.def.Functions.base = new Class(/** @lends CaboCity.t.def.Functions.base# */{
	/**
	 * @class Funciones que debe implementar cualquier objeto para definicir acciones de cosas del motor.
	 * @interface
	 * @constructs
	 * */
	initialize: function(){}
	/**
	 * Comprueba que el objeto esté bien-formado.
	 * @public
	 * @return {Boolean}
	 * */
	,isGoodFormed: function(){}
});

CaboCity.t.def.Functions.build = new Class(/** @lends CaboCity.t.def.Functions.build# */{
	Implements: CaboCity.t.def.Functions.base
	/**
	 * @class Objeto de definición de acciones para builds
	 * @constructs
	 * @implements CaboCity.t.def.Functions.base
	 * 
	 * @borrows CaboCity.t.def.Functions.base#isGoodFormed as #isGoodFormed
	 * 
	 * @param {CaboCity.t.def.Functions.build#checkParams} [checkParams=CaboCity.t.TrueFunc] Check if the params are corrects.
	 * @param {CaboCity.t.def.Functions.build#checkBuildPosibility} [checkBuildPosibility=CaboCity.t.TrueFunc] Checks for game-client part.
	 * @param {CaboCity.t.def.Functions.build#build} build Execs when "checkBuildPosibility()" function return **true**.
	 * 	After build it execute this.
	 * @param {CaboCity.t.def.Functions.build#notBuild} notBuild Execs when "checkBuildPosibility()" function return **false**.
	 * */
	,initialize: function(checkParams, checkBuildPosibility, build, notBuild){}

	,isGoodFormed: function(){
		//TO DO
	}
	
	/**
	 * Check if the params are corrects.
	 * @name CaboCity.t.def.Functions.build#checkParams
	 * @function
	 * 
	 * @param {TODOcommandArguments} argm
	 * @return {Boolean}
	 * */
	/**
	 * Checks for game-client part.
	 * @name CaboCity.t.def.Functions.build#checkBuildPosibility
	 * @function
	 * 
	 * @param {TODOcommandArguments} argm
	 * @return {Boolean}
	 * */
	/**
	 * Execs when "checkBuildPosibility()" function return **true**.
	 * 	After build the build it'll be executed.
	 * @name CaboCity.t.def.Functions.build#build
	 * @function
	 * 
	 * @param {TODOcommandArguments} argm
	 * @return {Boolean}
	 * */
	/**
	 * Execs when "checkBuildPosibility()" function return **false**.
	 * @name CaboCity.t.def.Functions.build#notBuild
	 * @function
	 * 
	 * @param {TODOcommandArguments} argm
	 * @return {Boolean}
	 * */
});

CaboCity.t.def.build = new Class(/** @lends CaboCity.t.def.build# */{
	/**
	 * @class Definición de un build.
	 * @constructs
	 * 
	 * @property {CaboCity.t.def.Functions.build} f Acciones del build.
	 * @property {Integer} id Identificador unívoco para la definición del build
	 * 
	 * */
	initialize: function(id, f){}
});

CaboCity.t.def.buildDef = new Class(/** @lends CaboCity.t.def.buildDef# */{
	/**
	 * @Class Contiene todas las definiciones correspondientes a los builds.
	 * @constructs
	 * */
	initialize: function(){}
	
	/**
	 * Listado de definiciones de builds
	 * @public
	 * @type CaboCity.t.def.build[]
	 * */
	,list: []

	/**
	 * Define un nuevo build y lo añade al listado.
	 * @public
	 * @param {CaboCity.t.def.build} buildDef
	 * */
	,addNew: function(buildDef){}
});

CaboCity.t.def.body = new Class(/** @lends CaboCity.t.def.body# */{
		/**
	 * @class Definición de un body.
	 * @constructs
	 * 
	 * @property {CaboCity.t.def.Functions.body} f Acciones del body.
	 * @property {Integer} id Identificador unívoco para la definición del body
	 * 
	 * */
	initialize: function(id, f){
		
	}
});

CaboCity.t.def.bodyDef = new Class(/** @lends CaboCity.t.def.BodyDef# */{
	/**
	 * @Class Contiene todas las definiciones correspondientes a los body.
	 * @constructs
	 * */
	initialize: function(){}
	
	/**
	 * Listado de definiciones de bodys
	 * @public
	 * @type {CaboCity.t.def.body} list
	 * */
	,list: []

	/**
	 * Define un nuevo body y lo añade al listado.
	 * @public
	 * @param {CaboCity.t.def.body} bodyDef
	 * */
	,addNew: function(bodyDef){}
});

CaboCity.t.def.Functions.body = new Class(/** @lends CaboCity.t.def.Functions.body# */{
	Implements: CaboCity.t.def.Functions.base
	/**
	 * @class Objeto para definir las acciones para la definición de bodys.
	 * @constructs
	 * @implements CaboCity.t.def.Functions.base
	 * 
	 * @borrows CaboCity.t.def.Functions.base#isGoodFormed as #isGoodFormed
	 * */
	,initialize: function(){
		
	}
});

CaboCity.t.Map = new Class(/** @lends CaboCity.t.Map# */{
	/**
	 * @class Toda la información de un mapa.
	 * @constructs
	 * @property {CaboCity.t.Size} size Tamaño en tiles del mapa.
	 * @property {CaboCity.t.List.build{}} build Listado de builds del mapa.
	 * */
	initialize: function(){
		
	}

	/**
	 * Procesa un mapa.
	 * @public
	 * */
	,processMap: function(){
		
	}
});

CaboCity.Views = new Class(/** @lends CaboCity.Views# */{
	/**
	 * @class Superobjeto para trabajar con las diferentes vistas de CaboCity.
	 * @constructs
	 * */
	initialize: function(){
		
	}
	/**
	 * Crea una ventana de login dentro del espacio de trabajo.
	 * @public
	 * */
	,createLogin: function(){}
	
	/**
	 * Crea un espacio de trabajo en la web.
	 * @public
	 * @param {CaboCity.t.Size} windowSize Tamaño del espacio de trabajo.
	 * */
	,createSpace: function(windowSize){}
	
	/**
	 * Crea un toolbar en la posición indicada.
	 * @public
	 * @param {'top'|'right'|'left'|'bottom'} borderPosition Posición donde se creará el toolbar.
	 * @param {CaboCity.t.Toolbar} toolbarActions Descripción del toolbar.
	 * */
	,createToolbar: function(borderPosition, toolbarActions){}
});

CaboCity.Interaction = new Class(/** @lends CaboCity.Interaction# */{
	/**
	 * @class Superobjeto Interaction con el mundo.
	 * @constructs
	 */
	initialize: function(){
		
	}

	/**
	 * Crea un nuevo mapa en la vista del jugador.
	 * @public
	 * 
	 * @param {CaboCity.t.Map} map Estructura del mapa que se debe mostrar en la vista de mapa.
	 */
	,loadMap: function(map){}
});

CaboCity.Interaction.Camera = new Class(/** @lends CaboCity.Interaction.Camera# */{
	/**
	 * @class Superobjeto para controlar la cámara.
	 * @constructs
	 * */
	initialize: function(){
		
	}
	/**
	 * Mueve la cámara a la posición indicada.
	 * @public
	 * 
	 * @param {CaboCity.t.Point} position Posición del mapa donde se tiene que mover la cámara.
	 * */
	,setCameraPosition: function(position){}
});




var newCaboCity;
function auxInit(){
	newCaboCity = new caboCity();
	newCaboCity.ini();
}

var caboCity = new Class({
	initialize: function(){
		this.touchpad = $('touchpad');
		this.cont = $('cont');
		this.canvas = $("grid"); //grid element
		
		this.ctx = this.canvas.getContext("2d"); //Canvas object
		this.grid = {};
		
		this.grid.start = {x: this.canvas.getSize().x/2 , y: this.canvas.getSize().y*0 }; //*px size*, not iso size.
		this.grid.sizes = {xleft: this.grid.start.x , xright: this.canvas.getSize().x-this.grid.start.x};
		
		this.action = {}; //Store action information data
		this.action.type = act.noaction;
		this.mouseLastPos = {}; //Store mouse position
		this.taked = Array();
	}
	,ini: function(){
		this.inivars();
		this.restartEvents();
		this.iniConnection();
		this.iniCommands();
		this.iniMap();
		
		this.iniVarRoad();
		this.iniBody();
		this.initVarsHouses();
		this.initEmpire();
		this.iniTime();
		
		this.draw();
	}
	, inivars: function(){		
		//The ISO SIZE of a tile in grid
		this.tile = {x: d.u.nisoGridBox.x/Math.cos(Math.PI/12) , y: d.u.nisoGridBox.y/Math.cos(Math.PI/12)};
		
		//NUMBER of tiles
		var c = {x: this.grid.sizes.xright/Math.cos(Math.PI/6) , y: this.grid.sizes.xleft/Math.cos(Math.PI/6)};
		this.grid.gridNum = {x: Math.floor(c.x/this.tile.x) , y: Math.floor(c.y/this.tile.y)}; //Number of iso tiles in gridctx.beginPath();
		this.grid.gridSize = {x: this.grid.gridNum.x*this.tile.x , y: this.grid.gridNum.y*this.tile.y};
		
		//Increment, in NONISO pixels, for an x position or y pos in grid
		this.grid.delta = {x: this.tile.x*Math.sin(Math.PI/3) , y: this.tile.y*Math.cos(Math.PI/3)};

		//Limit movement for grid
		this.grid.limitmove = {x: [-c.x, c.x] , y: [-c.y/2, c.y/2]};
	}
	
	/*Clean Canvas draw*/
	, cleanCanvas: function(){
		this.ctx.clearRect(0 ,0, this.canvas.getSize().x, this.canvas.getSize().y);
	}
	
	/*(re)Draw canvas*/
	, draw: function(){
		this.cleanCanvas(); //Clean canvas
		this.drawGrid(); //*Draw* grid
		this.drawFloor(); //Draw green
		
		this.createEmpirePath(); //Draw imperial road
	}
	, drawFloor: function(){
		var p = this.p({x: 0, y:0});
		var grass = new Element('div',{
			id: 'grass',
			styles: {
				width: this.grid.gridNum.x*20,
				height: this.grid.gridNum.y*20,
				top: p.y,
				left: p.x,
				"background-image": "url(grass1.jpg)"
			}
		});
		grass.addClass('isopers');
		grass.inject(this.cont);
		/*var img = new Image();
		img.src = 'grass1.jpg';
		var pos = this.p({x: 0, y:0});
		ctx.setTransform(Math.cos(45), -Math.sin(45) , Math.sin(45), Math.cos(45), 0, 0)
		//ctx.setTransform(1, -0.25 , -0.25, 1, 0, 0);
		ctx.drawImage(img, pos.x, pos.y);
		ctx.fill();*/
		
		/*for (var i = 0; i<this.grid.gridNum.x; ++i){
			for (var j=0; j<this.grid.gridNum.y; ++j){
				pos = this.p({x: i, y:j});
				
				var grassImg = new Image();
				img.src = 'img/grass1.jpg';
				ctx.drawImage(img, pos.x, pos.y);
				ctx.setTransform(1, 0.25 , -0.25, 1, 0, 0);
				
				var green = 100 + Math.random()*50; //random green from 100 to 200
				ctx.fillStyle = "rgb(0,"+Math.floor(green)+",0)";
				ctx.beginPath();
				ctx.moveTo(pos.x,pos.y);
				ctx.lineTo(pos.x+this.grid.delta.x , pos.y+this.grid.delta.y);
				ctx.lineTo(pos.x, pos.y+this.grid.delta.y*2);
				ctx.lineTo(pos.x-this.grid.delta.x, pos.y+this.grid.delta.y);
				ctx.fill();
			}
		}*/
	}
	
	/*Draw grid*/
	, drawGrid: function(){
		var start = this.grid.start;
		var finalp = {x: start.x+this.grid.gridSize.x*Math.cos(Math.PI/6) , y:this.grid.gridSize.y*Math.sin(Math.PI/6)};
		var cur = {x:start.x , y:start.y}; //The current position for the start of the line for grid - First the start of the first grid line
		
		//Draw left to right lines (rows)
		for(var i=0; i<=this.grid.gridNum.x; ++i){
			this.ctx.beginPath();
			this.ctx.moveTo(cur.x, cur.y);
			this.ctx.lineTo(finalp.x, finalp.y);
			this.ctx.closePath();
			this.ctx.stroke();
			
			cur.x -= this.grid.delta.x;
			cur.y += this.grid.delta.y;
			finalp.x -= this.grid.delta.x;
			finalp.y += this.grid.delta.y;
		}
		
		//finalp = {'x': start.x-(this.canvas.getSize().y-start.y)*Math.tan(Math.PI/3) , 'y': this.canvas.getSize().y};
		finalp = {x: start.x-this.grid.gridSize.x*Math.cos(Math.PI/6) , y: this.grid.gridSize.y*Math.sin(Math.PI/6)};
		cur = {x:start.x , y:start.y};
		//Draw right to left lines (columns)
		for(var i=0; i<=this.grid.gridNum.y; ++i){
			this.ctx.beginPath();
			this.ctx.moveTo(cur.x, cur.y);
			this.ctx.lineTo(finalp.x, finalp.y);
			this.ctx.closePath();
			this.ctx.stroke();
		
			cur.x += this.grid.delta.x;
			cur.y += this.grid.delta.y;
			finalp.x += this.grid.delta.x;
			finalp.y += this.grid.delta.y;
		}
	}
});

//Events
caboCity.implement({
	
	//Check mouse tiles position. If it is in a bad position return x,y = -1
	mousePositionInGrid: function(mx , my){
		//var delta = 10/Math.cos(Math.PI/6); //Unidad lado cuadrado en iso
		var ejex = mx - this.grid.start.x;
		var ejexiso = ejex/Math.cos(Math.PI/6); //+ la extensión de la "izquierda"
		var a = ejex*Math.tan(Math.PI/6);
		var h = my - this.grid.start.y;
		var hn = (h - a)/2;
		var eEjexiso = hn/Math.cos(Math.PI/3);
		ejexiso += eEjexiso;
		var poscx = Math.floor(ejexiso/this.tile.x); //x tile position
		
		//Bad mouse position in grid.
		if(poscx < 0 || poscx > this.grid.gridNum.x-1) poscx = -1;
		
		
		var ejey = this.grid.start.x - mx;
		var ejeyiso = ejey/Math.cos(Math.PI/6);
		var a = ejey*Math.tan(Math.PI/6);
		var h = my - this.grid.start.y;
		var hn = (h - a)/2;
		var eEjeyiso = hn/Math.cos(Math.PI/3);
		ejeyiso += eEjeyiso;
		var poscy = Math.floor(ejeyiso/this.tile.y);
		
		//Bad mouse position in grid.
		if(poscy < 0 || poscy > this.grid.gridNum.y-1) poscy = -1;
		
		return {x: poscx , y: poscy};
	}
	, restartEvents: function(){
		//Right clic menu disabled.
		this.canvas.addEvent('contextmenu', function(e){e.stop();});
		
		$('road').addEvent('click', function(e){
			e.stop();
			this.action.type = act.road;
			this.action.buffer = {};
			this.action.buffer.start = false;
			this.action.buffer.inix;
			this.action.buffer.iniy;
			this.action.buffer.endx;
			this.action.buffer.endy;
		}.bind(this));
		
		//Add new house Zone
		$('house').addEvent('click', function(e){
			e.stop();
			this.action.type = act.house;
			this.action.buffer = {}; //startcoor = {}; endcoor = {}
			this.action.buffer.started = false;
			this.action.buffer.ended = false;
		}.bind(this));
		
		$('cancelBuild').addEvent('click', function(e){
			e.stop();
			this.action.type = act.noaction;
			this.action.buffer = {};
			$$('.shadow , .removeEl').destroy();
		}.bind(this));
		
		$('removeBuild').addEvent('click', function(e){
			e.stop();
			this.action.type = act.remove;
			this.action.buffer = {};
		}.bind(this));
		
		$('newTable').addEvent('click', function(e){
			e.stop();
			window.location.reload();
		});
		
		//"Click" trigger for mouse.
		//You can add roads.
		this.touchpad.addEvent('click', function(e){
			if(!this.action.type) return; //No action
			var posm = e.page;
		
			posm.x -= this.cont.getPosition().x;
			posm.y -= this.cont.getPosition().y;
			
			var coor = this.mousePositionInGrid(posm.x , posm.y);
			if(coor.x == -1 || coor.y == -1) return;
			
			//Switch to the correct event function
			switch(this.action.type){
				case act.road: //build road
					if(!this.action.buffer.started){
						//If a road path hasn't started.
						this.action.buffer.started = true;
						this.action.buffer.startcoor = coor;
					} else if(this.action.buffer.started && this.action.buffer.ended && this.action.buffer.endcoor.x == coor.x && this.action.buffer.endcoor.y == coor.y) { //Double click at the same place
						this.newPath(this.action.buffer.startcoor, this.action.buffer.endcoor);
						this.action.buffer.started = false;
						this.action.buffer.ended = false;
					} else {
						this.action.buffer.ended = true;
						this.action.buffer.endcoor = coor;
						this.newPathShadow(this.action.buffer.startcoor, coor);
					}
				
					break;
				case act.house: //Add house zone
					if(!this.action.buffer.started){
						this.action.buffer.started = true;
						this.action.buffer.startcoor = coor;
					} else if(this.action.buffer.started && this.action.buffer.ended && this.action.buffer.endcoor.x == coor.x && this.action.buffer.endcoor.y == coor.y) { //"double click" at the same end position
						//Add new house zone.
						this.addNewHouseZone(this.action.buffer.startcoor , this.action.buffer.endcoor);
						this.action.buffer.started = false;
						this.action.buffer.ended = false;
					} else { //End click in another place.
						this.action.buffer.ended = true;
						this.action.buffer.endcoor = coor;
					}
					break;
				case act.remove:
					if(!this.action.buffer.started){
						this.action.buffer.started = true;
						this.action.buffer.startcoor = coor;
					} else if(this.action.buffer.started && this.action.buffer.ended && this.action.buffer.endcoor.x == coor.x && this.action.buffer.endcoor.y == coor.y){
						this.removeZone(this.action.buffer.startcoor , this.action.buffer.endcoor);
						this.action.buffer.started = false;
						this.action.buffer.ended = false;
					} else {
						this.action.buffer.ended = true;
						this.action.buffer.endcoor = coor;
						this.warningRemove(this.action.buffer.startcoor, coor);
					}
					break;
			}
		
		}.bind(this));
		
		new Drag(this.cont, {
			limit: this.grid.limitmove
			, handle: this.touchpad
			, onStart: function(){
				if(newCaboCity.action.type != act.noaction)
					this.stop(); //It can't moves if it have an action attached.
			}
		});
		
		//MOUSEMOVE EVENT FOR SHADOWSroadClass
		//For mouse shadows position
		this.touchpad.addEvent('mousemove', function(e){
			if(this.action.type == act.noaction) return; //No action
			var posm = e.page;
			
			posm.x -= this.cont.getPosition().x;
			posm.y -= this.cont.getPosition().y;
			
			var coor = this.mousePositionInGrid(posm.x , posm.y);
			if(coor.x == -1 || coor.y == -1) return;
		
			//Si el cuadrado es diferente
			if(this.mouseLastPos.x != coor.x || this.mouseLastPos.y != coor.y){
				//this.draw(); //restart shadow to "nothing"
				this.mouseLastPos = coor;
				
				switch(this.action.type){
					case act.road: //Road
						if( !this.action.buffer.started ){
							this.newPathShadow(coor, coor);
						} else if(this.action.buffer.started && !this.action.buffer.ended){
							//Path Shadow
							this.newPathShadow(this.action.buffer.startcoor, coor);
						} //else NOT redraw nothing
						break;
					
					case act.house: //house
						if(!this.action.buffer.started){ //Nothing before.
							this.addHouseZoneShadow(coor , coor);
							//Print house zone shadow in tile.
						} else if(this.action.buffer.started && !this.action.buffer.ended) { //Start coor zone but no end zone
							this.addHouseZoneShadow(this.action.buffer.startcoor , coor);
						} //else do nothing (but last shadow persist).
						break;
					case act.remove:
						if(!this.action.buffer.started){
							this.warningRemove(coor, coor);
						} else if(this.action.buffer.started && !this.action.buffer.ended){
							this.warningRemove(this.action.buffer.startcoor, coor);
						}
						break;
				}
			}

		}.bind(this));
	}
});

//Manipulation
caboCity.implement({
	error: function(msg){
		console.log(msg);
	}
	
	//Real array length (withouth null items)
	,l: function(arr){
		var size = 0;
		arr.each(function(item){
			if(item) size++;
		});
		return size;
	}
	, adjustCoordinates : function(coor, size){
		var newcoor = {};
		if(this.grid.gridNum.x-coor.x <= size.x) newcoor.x = this.grid.gridNum.x-size.x;
		else newcoor.x = coor.x;
		if(this.grid.gridNum.y-coor.y <= size.y) newcoor.y = this.grid.gridNum.y-size.y;
		else newcoor.y = coor.y;
		
		return {x: newcoor.x , y: newcoor.y};
	}
	,vec2coor: function(vec){
		var coor = {x: vec%this.grid.gridNum.x , y: Math.floor(vec/this.grid.gridNum.x)  };
		return coor;
	}
	
	//-1 means bad coordinate.
	, coor2vec: function(coor){
		if(coor.x >= this.grid.gridNum.x || coor.x < 0) return -1;
		if(coor.y >= this.grid.gridNum.y || coor.y < 0) return -1;
		var vec = coor.y*this.grid.gridNum.x + coor.x;
		return vec;
	}
	, getTypeTile: function(coor){
		return this.taked[ this.coor2vec(coor) ];
	}
	, isTileBuildable: function(coor){
		if(!this.taked[ this.coor2vec(coor) ])
			return true;
		else
			return false;
	}
	, freeThisTile: function(coor){
		this.taked[ this.coor2vec(coor) ] = null;
	}
	, takeThisTile : function(coor, type){
		this.taked[ this.coor2vec(coor) ] = type;
	}
	
	/*Converto coordinate to px*/
	,p : function(coor) {
		//Calculate grid px position
		var posx = this.grid.start.x + this.grid.delta.x*coor.x - this.grid.delta.x*coor.y;
		var posy = this.grid.start.y + this.grid.delta.y*coor.y + this.grid.delta.y*coor.x;
		
		//Adjust to real canvas position
		//posy = posy+this.cont.getPosition().y;
		//posx = posx+this.cont.getPosition().x;
		
		return {x: posx , y: posy};
	}
	,warningRemove: function(startcoor, endcoor){
		$$('.removeEl').destroy();
		
		//Element sizes and *correct position coordinates*
		if(startcoor.x < endcoor.x) {
			var w = endcoor.x - startcoor.x +1;
			var px = startcoor.x;
		} else {
			var w = startcoor.x - endcoor.x +1;
			var px = startcoor.x-w+1;
		}
		if(startcoor.y < endcoor.y) {
			var h = endcoor.y - startcoor.y +1;
			var py = startcoor.y;
		} else {
			var h = startcoor.y - endcoor.y +1;
			var py = startcoor.y-h+1;
		}
		var pos = this.p({x: px, y: py});
		var el = new Element('div', {
			styles: {
				width: w*d.u.nisoGridBox.x,
				height: h*d.u.nisoGridBox.y,
				left: pos.x,
				top: pos.y
			}
		});
		el.addClass("removeEl").addClass("isoPers");
		el.inject(this.cont);
	}
	, removeEl: function(coor){
		var tileType = this.getTypeTile(coor);
		switch(tileType){
			case d.tt.road:
				this.removeRoad(coor);
				break;
			case d.tt.houseZoneTile:
				this.removeHouse(coor);
				break;
			default:
		}
	}
	,removeZone: function(startcoor, endcoor){
		if(startcoor.x < endcoor.x){ var fromx = startcoor.x; var tox = endcoor.x;}
		else {var fromx = endcoor.x; var tox = startcoor.x;}
		if(startcoor.y < endcoor.y) { var fromy = startcoor.y; var toy = endcoor.y;}
		else { var fromy = endcoor.y; var toy = startcoor.y;}
		for(var i=fromx; i<=tox; ++i){
			for(var j=fromy; j<=toy; ++j){
				this.removeEl({x: i, y:j});
			}
		}
		$$('.removeEl').destroy();
	}
});

//Time
caboCity.implement({
	iniTime: function(){
		this.year = 0;
		this.month = 1;// [1-12]
		
		
		this.newMonthID = this.newMonth.periodical( d.emp.month, this);
		
		//Update time in panel
		if(d.config.EPV) editorPanel.timeRoot();
	}
	,newMonth: function(){
		console.log("Nuevo mes");
		if(this.month == 12){
			this.month = 1;
			this.year++;
		} else {
			this.month++;
		}
		
		//Check for new inmigrants for come to city.
		this.checkForNewInmigrants();
	}
});

//Roads
caboCity.implement({
	convertToPathList: function(inicoor, endcoor){
		var iniX = inicoor.x;
		var iniY = inicoor.y;
		var endX = endcoor.x;
		var endY = endcoor.y;

		var actX = iniX;
		var actY = iniY;
		var list = Array();
	
		//Alguna sugerencia?
		while(actX != endX || actY != endY){
			if(actX == endX ){
				if(actY < endY){
					for(; actY <= endY; actY++)
						list.include({'x': actX , 'y': actY});
					actY--;
				} else {
					for(; actY >= endY; actY--)
						list.include({'x': actX , 'y': actY});
					actY++;
				}
				break;
			}
			if(actY == endY ) {
				if(actX < endX){
					for(; actX <= endX; actX++)
						list.include({'x': actX , 'y': actY});
					actX--;
				} else {
					for(; actX >= endX; actX--)
						list.include({'x': actX , 'y': actY});
					actX++;
				}
				break;
			}
		
			if(actY < endY) {
				for(; actY <= endY; actY++)
					list.include({'x': actX , 'y': actY});
				actY--;
			} else {
				for(; actY >= endY; actY--)
					list.include({'x': actX , 'y': actY});
				actY++;
			}
		}
	
		if(list.length == 0)
			list.include({'x': actX , 'y': actY});
	
		return list;
	}
});
